﻿using System;
using DataService.Enums;
using DataService.Group;
using DataService.Structs;

namespace DataService.Tag;

public abstract class TagBase : IComparable<TagBase>
{
    protected short _id;
    public short ID => _id;

    protected bool _active = true;
    public bool Active
    {
        get => _active;
        set
        {
            _group.SetActiveState(value, _id);
            _active = value;
        }
    }

    protected QUALITIES _quality;
    public QUALITIES Quality => _quality;

    protected Storage _value;
    public Storage Value => _value;

    protected DateTime _timestamp = DateTime.MinValue;
    public DateTime Timestamp => _timestamp;

    protected DeviceAddress _plcAddress;
    public DeviceAddress Address
    {
        get => _plcAddress;
        set => _plcAddress = value;
    }

    protected IGroup _group;
    public IGroup Parent => _group;

    protected TagBase(short id, DeviceAddress address, IGroup group)
    {
        _id = id;
        _group = group;
        _plcAddress = address;
    }

    public void Update(Storage newvalue, DateTime timeStamp, QUALITIES quality)
    {
        if (_timestamp > timeStamp) return;//如果时间戳更旧或值未改变
        if (ValueChanging != null)
        {
            ValueChanging(this, new ValueChangingEventArgs<Storage>(quality, _value, newvalue, _timestamp, timeStamp));
        }
        _timestamp = timeStamp;
        _quality = quality;
        if (quality == QUALITIES.QUALITY_GOOD)
        {
            _value = newvalue;
            if (ValueChanged != null)
            {
                ValueChanged(this, new ValueChangedEventArgs(_value));
            }
        }
    }

    public abstract bool Refresh(DataSource source = DataSource.Device);

    public abstract Storage Read(DataSource source = DataSource.Cache);

    protected abstract int InnerWrite(Storage value);

    public abstract int Write(object value);

    public int Write(Storage value, bool bForce)
    {
        DateTime time = DateTime.Now;
        _timestamp = time;
        if (bForce)
        {
            if (ValueChanging != null)
            {
                ValueChanging(this, new ValueChangingEventArgs<Storage>(QUALITIES.QUALITY_GOOD, _value, value, _timestamp, time));
            }
        }
        int result = InnerWrite(value);
        if (bForce || result != 0)
        {
            var data = Read(DataSource.Device);
            if (data != value)
            {
                time = DateTime.Now;
                if (ValueChanging != null)
                {
                    ValueChanging(this, new ValueChangingEventArgs<Storage>(QUALITIES.QUALITY_GOOD, _value, data, _timestamp, time));
                }
                _value = data;
                _timestamp = time;
                return result;
            }
        }
        return 0;
    }

    public ValueChangingEventHandler<Storage> ValueChanging;

    public ValueChangedEventHandler ValueChanged;

    #region IComparable<PLCAddress> Members

    public override int GetHashCode()
    {
        return _id.GetHashCode();
    }

    public int CompareTo(TagBase other)
    {
        return _plcAddress.CompareTo(other._plcAddress);
    }

    #endregion
}

public delegate void ValueChangingEventHandler<T>(object sender, ValueChangingEventArgs<T> e);
public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
